<?php
namespace Api\Libs;

class Upload {

    /**
     * 文件上传函数
     * @param $type 文件类型
     * @param bool $cut 图片是否裁剪
     * @param bool $thumb 是否有缩略图
     * @param array $size 图片尺寸参数
     * @return array
     */
    public function upload($type,$cut=false,$thumb=false,$size = null) {

        // 读取文件上传路径
        $uploadPath = C ('UPLOAD_PATH');

        // 判断上传文件类型
        if (empty($type)) return array('status'=>0,'msg'=>'文件类型不能为空');

        $fileTypes = array('img','file','video','apk');
        if (!in_array($type,$fileTypes)) return array('status'=>0,'msg'=>'不支持的文件类型');

        $path = $uploadPath.$type.DIRECTORY_SEPARATOR.date('Y-m-d');

        // 物理路径
        $absPath = $_SERVER['DOCUMENT_ROOT'].$path;


        $cleanupTargetDir = true; // 删除同名旧文件
        $maxFileAge = 5 * 3600; // 缓存时间

        if (!file_exists($absPath)) {
            @mkdir($absPath);
        }

        // 获取文件名称
        if (isset($_REQUEST["name"])) {
            $fileName = $_REQUEST["name"];
        } elseif (!empty($_FILES)) {
            $fileName = $_FILES["file"]["name"];
        } else {
            $fileName = uniqid("file_");
        }

        // 验证文件格式
        if (!$this->verify($fileName)) return array('status'=>0,'msg'=>'不支持该文件类型');

        $filePath = $absPath . DIRECTORY_SEPARATOR . $fileName;
        $dbFilePath = $path . DIRECTORY_SEPARATOR . $fileName;

        // Chunking might be enabled
        $chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
        $chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 0;


        // 删除旧文件
        if ($cleanupTargetDir) {
            if (!is_dir($absPath) || !$dir = opendir($absPath)) {
                return array(
                    'status' => 0,
                    'msg' => '无法打开文件上传目录'
                );
            }

            while (($file = readdir($dir)) !== false) {
                $tmpfilePath = $absPath . DIRECTORY_SEPARATOR . $file;

                // If temp file is current file proceed to the next
                if ($tmpfilePath == "{$filePath}.part") {
                    continue;
                }

                // Remove temp file if it is older than the max age and is not the current file
                if (preg_match('/\.part$/', $file) && (filemtime($tmpfilePath) < time() - $maxFileAge)) {
                    @unlink($tmpfilePath);
                }
            }
            closedir($dir);
        }


        // 打开缓存文件
        if (!$out = @fopen("{$filePath}.part", $chunks ? "ab" : "wb")) {
            return array(
                'status' => 0,
                'msg' => '无法打开文件上传目录'
            );
        }

        if (!empty($_FILES)) {
            if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
                return array(
                    'status' => 0,
                    'msg' => '移动上传文件失败'
                );
            }

            // Read binary input stream and append it to temp file
            if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
                return array(
                    'status' => 0,
                    'msg' => '打开文件流失败'
                );
            }
        } else {
            if (!$in = @fopen("php://input", "rb")) {
                return array(
                    'status' => 0,
                    'msg' => '打开文件流失败'
                );
            }
        }

        // 写入文件
        while ($buff = fread($in, 4096)) {
            fwrite($out, $buff);
        }

        @fclose($out);
        @fclose($in);

        // 重命名文件
        if (!$chunks || $chunk == $chunks - 1) {
            rename("{$filePath}.part", $filePath);
        }

        // 裁剪图片 [裁剪图片必须制定图片的宽和高]
        if ($type === 'img' && $cut && !empty($size)) {
            if(!$this->cut($filePath,$size,$thumb)){
                return array(
                    'status' => 2,
                    'msg' => '图片裁剪或生成缩略图失败',
                    'path' => $dbFilePath
                );
            }
        }

        return array(
            'status' => 1,
            'msg' => '上传成功',
            'path' => $dbFilePath
        );
    }

    /**
     * 验证文件格式
     * @param $fileName
     */
    private function verify($fileName) {
        $suffix = substr(strchr($fileName,'.'),1);
        $suffixArr = array ('png','jpg','jpeg','gif','PNG','JPG','JPEG','GIF','doc','docx','xls','xlsx','txt','zip','7z','rar','apk','APK');
        return in_array($suffix,$suffixArr);
    }


    /**
     * 图片裁剪函数
     * @param string $path
     * @param  array $size
     * @param bool $thumb
     * @return bool
     */
    private function cut($path,$size,$thumb=false){
        $width = $size['width'];
        $height = $size['height'];
        if (empty($width) || empty($height)) return false;

        // 获取文件后缀名
        $suffix = substr(strchr($path,'.'),1);

        // 获取文件原始参数[宽，高]
        list($width_orig, $height_orig) = getimagesize($path);
        // 获取宽高比
        $ratio_orig = $width_orig/$height_orig;

        // 计算图片等比例缩放参数
        if ($width/$height > $ratio_orig) {
            $width = $height*$ratio_orig;
        } else {
            $height = $width/$ratio_orig;
        }

        // jpg 定位到 jpeg
        if ($suffix === 'jpg' || $suffix == 'JPG') $suffix='jpeg';

        // 按照新尺寸创建一个彩色底纹图片
        $image_p = imagecreatetruecolor($width, $height);
        $image = $this->imgcreatefrom($suffix,$path);

        // 重绘
        if (!imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig)){
            return false;
        }

        // 如果是生成缩略图,重新配置路径
        if ($thumb) {
            $file_name = substr(strrchr($path,DIRECTORY_SEPARATOR),1);
            $path = str_replace($file_name,'thumb_'.$file_name,$path);
        }

        //echo $path;
        // 将新图片写入到文件
        $this->imgcanvas($suffix,$image_p, $path);
        imagedestroy($image);

        return true;
    }

    // 图片重绘函数辅助函数
    private function imgcreatefrom($type,$path) {
        switch ($type) {
            case 'jpg':
            case 'JPG':
            case 'JPEG':
            case 'jpeg': return imagecreatefromjpeg($path);
            case 'PNG':
            case 'png': return imagecreatefrompng($path);
            case 'GIF':
            case 'gif': return imagecreatefromgif($path);
        }
    }

    // 图片重绘函数辅助函数
    private function imgcanvas($type,$image_p,$path) {
        switch ($type) {
            case 'jpg':
            case 'JPG':
            case 'JPEG':
            case 'jpeg': return imagejpeg($image_p,$path);
            case 'PNG':
            case 'png': return imagepng($image_p,$path);
            case 'GIF':
            case 'gif': return imagegif($image_p,$path);
        }
    }

    // 删除文件
    private function delete($path)
    {
        $fullPath = $_SERVER['DOCUMENT_ROOT'] . $path;
        if (file_exists($fullPath))
            @unlink($fullPath);
    }


    /**
     * 系统文件上传函数
     * @param unknown_type $type 文件上传类型
     * @param unknown_type $thumb 是否生成缩略图
     * @param unknown_type $path 返回路径还是上传文件对象
     * @return String | Object
     */
    function _upload($type,$thumb = false,$path=true){
        // 上传文件类型
        $ext_arr = array(
            'img' => array('gif', 'jpg', 'jpeg', 'png', 'bmp', 'GIF','JPG','JPEG','PNG','BMP'),
            'video' => array('swf', 'flv', 'mp3', 'wav', 'wma', 'wmv', 'mid', 'avi', 'mpg', 'asf', 'rm', 'rmvb'),
            'file' => array('doc', 'docx', 'xls', 'xlsx', 'ppt', 'htm', 'html', 'txt', 'zip', 'rar', 'gz', 'bz2','pdf'),
            'apk' => array('apk','APK')
        );

        $upload = new \Think\Upload();// 实例化上传类
        $upload->maxSize   =     3145728 ;// 设置附件上传大小
        $upload->autoSub = true;//使用子目录保存上传文件
        $upload->subType = 'date';//使用日期模式创建子目录
        $upload->dateFormat = 'Ymd';//设置子目录日期格式
        $upload->allowExts  = $ext_arr[$type];// 设置附件上传类型
        $upload->rootPath = "./Public/Uploads/";
        $upload->savePath =  $type."/";// 设置附件上传目录
        $upload->thumb = $thumb;//生成缩略图
        $upload->thumbPrefix = 'thumb_';
        $upload->thumbMaxWidth = '200';//缩略图最大宽度
        $upload->thumbMaxHeight = '200';//缩略图最大高度
        $upload->thumbRemoveOrigin = true;

        // 上传文件
        $info   =   $upload->upload();
        if(!$info) {
            // 上传错误提示错误信息
            $this->error($upload->getError());
        }else{
            // 上传成功 获取上传文件信息
            if ($path){
                foreach($info as $file){
                    return $file['savepath'].$file['savename'];
                }
            } else {
                return $info;
            }
        }
    }

}